import 'package:dio/dio.dart';
import 'package:enjoy_plus/utils/eventbus.dart';
import 'package:enjoy_plus/utils/toast.dart';
import 'package:enjoy_plus/utils/token.dart';

// 统一响应格式
interface class ApiResponse<T> {
  final int code;
  final String message;
  final T? data;

  ApiResponse({
    required this.code,
    required this.message,
    this.data,
  });

  factory ApiResponse.fromJson(
      Map<String, dynamic> json, T? Function(dynamic) fromJson) {
    return ApiResponse(
      code: json['code'] as int,
      message: json['message'] as String,
      data: json['data'] == null ? null : fromJson(json['data']),
    );
  }
}

// 网络配置
interface class NetworkConfig {
  final String baseUrl;
  final Duration connectTimeout;
  final Duration receiveTimeout;
  final Map<String, dynamic> headers;

  const NetworkConfig({
    required this.baseUrl,
    this.connectTimeout = const Duration(seconds: 5),
    this.receiveTimeout = const Duration(seconds: 5),
    this.headers = const {'Content-Type': 'application/json'},
  });
}

// 自定义错误
class NetworkError implements Exception {
  final String message;
  final int? code;
  final dynamic data;

  NetworkError({
    required this.message,
    this.code,
    this.data,
  });

  @override
  String toString() => message;
}

class NetworkService {
  late final Dio _dio;
  final NetworkConfig config;

  NetworkService({
    this.config = const NetworkConfig(
      baseUrl: 'https://live-api.itheima.net',
    ),
  }) {
    _dio = Dio()
      ..options.baseUrl = config.baseUrl
      ..options.connectTimeout = config.connectTimeout
      ..options.receiveTimeout = config.receiveTimeout
      ..options.headers = config.headers;

    _addInterceptors();
  }

  Future<T> get<T>(
    String url, {
    Map<String, dynamic>? params,
    T Function(dynamic)? fromJson,
  }) async {
    try {
      final response = await _dio.get(
        url,
        queryParameters: params,
        options: Options(extra: {'fromJson': fromJson}),
      );
      return response.data;
    } catch (e) {
      rethrow;
    }
  }

  Future<T> post<T>(
    String url,
    dynamic data, {
    T Function(dynamic)? fromJson,
  }) async {
    try {
      final response = await _dio.post(
        url,
        data: data,
        options: Options(extra: {'fromJson': fromJson}),
      );
      return response.data;
    } catch (e) {
      rethrow;
    }
  }

  Future<T> put<T>(
    String url,
    dynamic data, {
    T Function(dynamic)? fromJson,
  }) async {
    try {
      final response = await _dio.put(
        url,
        data: data,
        options: Options(extra: {'fromJson': fromJson}),
      );
      return response.data;
    } catch (e) {
      rethrow;
    }
  }

  // 添加刷新token的方法
  Future<bool> _refreshToken(String refreshToken) async {
    try {
      Dio dio = Dio();
      final response = await dio.post(
        '${config.baseUrl}/refreshToken',
        options: Options(headers: {'Authorization': 'Bearer $refreshToken'}),
      );

      if (response.statusCode == 200 && response.data['code'] == 10000) {
        final newToken = response.data['data']['token'] as String;
        final newRefreshToken = response.data['data']['refreshToken'] as String;

        // 保存新的token
        await TokenManager().saveToken(newToken, newRefreshToken);
        return true;
      }
      return false;
    } catch (e) {
      return false;
    }
  }

  void _addInterceptors() {
    _dio.interceptors.add(InterceptorsWrapper(
      onRequest: (options, handler) async {
        final token = TokenManager().getToken();
        if (token != null) {
          options.headers['Authorization'] = 'Bearer $token';
        }
        handler.next(options);
      },
      onResponse: (response, handler) {
        if (response.statusCode! >= 200 && response.statusCode! < 300) {
          final apiResponse = ApiResponse.fromJson(
            response.data,
            response.requestOptions.extra['fromJson'] ?? ((data) => data),
          );

          if (apiResponse.code == 10000) {
            // 直接resolve转换后的数据
            handler.resolve(Response(
              requestOptions: response.requestOptions,
              data: apiResponse.data,
              statusCode: response.statusCode,
              statusMessage: response.statusMessage,
            ));
          } else {
            ToastUtil.showError(apiResponse.message);
            handler.reject(
              DioException(
                requestOptions: response.requestOptions,
                error: NetworkError(
                  message: apiResponse.message,
                  code: apiResponse.code,
                  data: apiResponse.data,
                ),
              ),
            );
          }
        } else {
          handler.reject(
            DioException(
              requestOptions: response.requestOptions,
              error: NetworkError(message: '请求失败，状态码：${response.statusCode}'),
            ),
          );
        }
      },
      onError: (error, handler) async {
        if (error.type == DioExceptionType.badResponse &&
            error.response?.statusCode == 401) {
          final refreshToken = TokenManager().getRefreshToken();
          if (refreshToken != null) {
            // 尝试刷新token
            final success = await _refreshToken(refreshToken);
            if (success) {
              // 获取新token
              // 重试之前失败的请求
              final response = await _dio.fetch(error.requestOptions);
              return handler.resolve(response);
            }
          }

          // 刷新失败，清除token并触发登出事件
          TokenManager().removeToken();
          eventBus.fire(LogoutEvent('登录已过期'));
          handler.reject(
            DioException(
              requestOptions: error.requestOptions,
              error: NetworkError(message: '登录已过期'),
            ),
          );
          return;
        }

        final message = switch (error.type) {
          DioExceptionType.connectionTimeout ||
          DioExceptionType.receiveTimeout =>
            '网络连接超时',
          DioExceptionType.badResponse => '响应错误：${error.response?.statusCode}',
          _ => '网络请求错误：${error.message}',
        };

        handler.reject(
          DioException(
            requestOptions: error.requestOptions,
            error: NetworkError(
              message: message,
              code: error.response?.statusCode,
              data: error.response?.data,
            ),
          ),
        );
      },
    ));
  }
}

// 导出
final http = NetworkService();
